package ldh.im.fxgui.component;

import com.jfoenix.controls.JFXButton;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.robot.Robot;
import javafx.scene.shape.Rectangle;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import ldh.im.fxbase.component.MaskPane;
import ldh.im.fxbase.util.IconUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

// 桌面选择区域
public class ScreenSelectView extends Stage {

    private transient Stage parentStage = null;
    private Scene scene = null;
    private Rectangle rectangle = new Rectangle();
    private JFXButton submitBtn = new JFXButton();
    private JFXButton closeBtn = new JFXButton();
    private JFXButton fullScreenBtn = new JFXButton();    // 录制全屏
    private HBox controlPane = new HBox();
    private Label positionLabel = new Label();
    private Label tip = new Label("开始选择区域");
    private MaskPane maskPane = new MaskPane();
    private List<Rectangle> dragRectangles = new ArrayList<>();  // 移动小手柄

    private boolean canCapture = true;
    private Point2D origin = null;
    private Screen screen = null;
    private Robot robot = new Robot();
    private ImageView fullScreenImageView = new ImageView();

    private Consumer<Rectangle> captureConsumer;

    private AnchorPane root;

    public ScreenSelectView(Stage parentStage, Consumer<Rectangle> captureConsumer) {
        this.parentStage = parentStage;
        this.captureConsumer = captureConsumer;
        root = new AnchorPane();

        screen = Screen.getPrimary(); //getScreen(webView);
        root.setStyle("-fx-background-color: rgb(0,0,0,0.01)");

        rectangle.setFill(Color.TRANSPARENT);
        rectangle.setStroke(Color.GREEN);
        submitBtn.setGraphic(IconUtil.createIcon("fa-check", 16, Color.BLUE));
        submitBtn.setTooltip(new Tooltip("确认"));
        submitBtn.setOnAction((e)->{
            this.close();

            Rectangle rectangle2D = new Rectangle(rectangle.getWidth()-2, rectangle.getHeight()-2);
            rectangle2D.setX(rectangle.getX()-1);
            rectangle2D.setY(rectangle.getY()-1);
            captureConsumer.accept(rectangle2D);
        });

        closeBtn.setGraphic(IconUtil.createIcon("fa-close", 16, Color.RED));
        closeBtn.setTooltip(new Tooltip("关闭"));
        closeBtn.setOnAction((e)->{
            this.close();

            parentStage.setAlwaysOnTop(true);
            parentStage.setIconified(false);
        });

        fullScreenBtn.setGraphic(IconUtil.createIcon("ion-arrow-move", 16, Color.GREEN));
        fullScreenBtn.setTooltip(new Tooltip("全屏录制"));
        fullScreenBtn.setOnAction(e->{
            double width = screen.getBounds().getWidth();
            double height = screen.getBounds().getHeight();
            rectangle.setX(0);
            rectangle.setY(0);
            maskPane.setVisible(true);
            rectangle.setWidth(width);
            rectangle.setHeight(height);
            calcPosition();
        });
        Region region1 = new Region();
        Region region2 = new Region();

        controlPane.setStyle("-fx-background-color: #f8f8ff");
        controlPane.setMinWidth(300);
        controlPane.setMaxHeight(26);
        controlPane.setVisible(false);
        controlPane.setAlignment(Pos.CENTER);
        controlPane.getChildren().addAll(positionLabel, region1, fullScreenBtn, region2, closeBtn, submitBtn);

        HBox.setHgrow(region1, Priority.ALWAYS);
        HBox.setHgrow(region2, Priority.ALWAYS);

        maskPane.setOpacity(0.4);

        tip.setStyle("-fx-text-fill: yellow; -fx-font-size: 30px; ");
        tip.setLayoutX((screen.getBounds().getWidth()-100)/2);
        tip.setLayoutY(100);

        root.getChildren().addAll(fullScreenImageView, tip, rectangle); // , position, canvas, controlPane
        initDragRectangles();
        root.getChildren().addAll(maskPane, controlPane); // , position, canvas, controlPane

        initBind();

        scene = new Scene(root);
        scene.setFill(Color.TRANSPARENT);

        this.setMaximized(true);
        this.setScene(scene);
        this.initStyle(StageStyle.TRANSPARENT);
//        this.initModality(Modality.WINDOW_MODAL);
        this.initOwner(parentStage);

        initEvent();

        captureFullScreen();

        playTipAnination();
    }

    public void initRectangle(Rectangle rectangle) {
        this.rectangle.setX(rectangle.getX());
        this.rectangle.setY(rectangle.getY());
        this.rectangle.setWidth(rectangle.getWidth());
        this.rectangle.setHeight(rectangle.getHeight());
        controlPane.setVisible(true);
        calcPosition();
    }

    private void initDragRectangles() {
        for(int i=0; i<8; i++) {
            Rectangle rectangle = new Rectangle(4, 4);
            rectangle.setFill(Color.GREEN);
            root.getChildren().add(rectangle);
            dragRectangles.add(rectangle);
        }
        initDragEvent();
    }

    private void initDragEvent() {
        for(int i=0; i<8; i++) {
            Rectangle rectangle = dragRectangles.get(i);
        }
    }

    private void initBind() {
        rectangle.widthProperty().addListener((InvalidationListener)l->dragRectangles());
        rectangle.heightProperty().addListener((InvalidationListener)l->dragRectangles());

        maskPane.xProperty().bind(rectangle.xProperty());
        maskPane.yProperty().bind(rectangle.yProperty());

        maskPane.hProperty().bind(rectangle.heightProperty());
        maskPane.wProperty().bind(rectangle.widthProperty());
    }

    private void initEvent() {
        root.setOnMousePressed(e->{
            if(!canCapture) return;
            controlPane.setVisible(true);
            maskPane.setVisible(true);
            origin = new Point2D(e.getScreenX(), e.getScreenY());
            rectangle.setWidth(0);
            rectangle.setHeight(0);
            rectangle.setX(origin.getX());
            rectangle.setY(origin.getY());
            calcPosition();
        });

        root.setOnMouseDragged(e->{
            if(!canCapture) return;

            double nx = e.getScreenX();
            double ny = e.getScreenY();

            rectangle.setWidth((int)Math.abs(nx-origin.getX()));
            rectangle.setHeight((int)Math.abs(ny-origin.getY()));

            if (nx >= origin.getX() && e.getScreenY() >= origin.getY()) {
                rectangle.setX(origin.getX());
                rectangle.setY(origin.getY());
            } else if (nx >= origin.getX() && ny < origin.getY()) {
                rectangle.setX(origin.getX());
                rectangle.setY(ny);
            } else if (nx < origin.getX() && ny >= origin.getY()) {
                rectangle.setX(nx);
                rectangle.setY(origin.getY());
            } else {
                rectangle.setX(nx);
                rectangle.setY(ny);
            }
            rectangle.setX((int)rectangle.getX());
            rectangle.setY((int)rectangle.getY());
            calcPosition();
        });
        root.setOnMouseReleased(e->{
            if(!canCapture) return;
            if (rectangle.getWidth() < 5 && rectangle.getHeight() < 5) return;

            rectangle.setWidth((int)Math.abs(e.getScreenX()-origin.getX()));
            rectangle.setHeight((int)Math.abs(e.getScreenY()-origin.getY()));
        });

        this.getScene().setOnKeyPressed(e->{
            if (e.isControlDown()) {
                if (e.getCode() == KeyCode.LEFT) {
                    moveCaptureRectangleWidth(-1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.RIGHT) {
                    moveCaptureRectangleWidth(1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.UP) {
                    moveCaptureRectangleHeight(-1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.DOWN) {
                    moveCaptureRectangleHeight(1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.ESCAPE) {
                    parentStage.setAlwaysOnTop(true);
                    parentStage.setIconified(false);
                    this.close();
                }
            } else {
                if (e.getCode() == KeyCode.LEFT) {
                    moveCaptureRectangleX(-1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.RIGHT) {
                    moveCaptureRectangleX(1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.UP) {
                    moveCaptureRectangleY(-1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.DOWN) {
                    moveCaptureRectangleY(1);
                    moveRectangle();
                } else if (e.getCode() == KeyCode.ESCAPE) {
                    parentStage.setAlwaysOnTop(true);
                    parentStage.setIconified(false);
                    this.close();
                }
            }

        });
        this.getScene().setOnKeyReleased(e->{
            if (canCapture) {
                calcPosition();
                rectangle.requestFocus();
            }
        });
    }

    private boolean moveCaptureRectangleX(int x) {
        boolean movable = true;
        double nx = rectangle.getX() + x;
        nx = nx > 0 ? nx : 0;
        movable = nx != 0;
        if (nx + rectangle.getWidth() >= screen.getBounds().getWidth()) {
            nx = screen.getBounds().getWidth() - rectangle.getWidth();
            movable = false;
        }
        rectangle.setX(nx);

        if (Double.compare(rectangle.getWidth(), 0.0) == 0) {
            origin = origin.add(new Point2D(x, 0));
        }
        return movable;
    }

    private boolean moveCaptureRectangleY(int x) {
        boolean movable = true;
        double nx = rectangle.getY() + x;
        nx = nx > 0 ? nx : 0;
        movable = nx != 0;
        if (nx + rectangle.getHeight() >= screen.getBounds().getHeight()) {
            nx = screen.getBounds().getHeight() - rectangle.getHeight();
            movable = false;
        }
        rectangle.setY(nx);
        if (Double.compare(rectangle.getHeight(), 0.0) == 0) {
            origin = origin.add(new Point2D(0, x));
        }
        return movable;
    }

    private void moveCaptureRectangleWidth(int n) {
        if(rectangle.getWidth() <= 0.0) return;
        if (rectangle.getX() + rectangle.getWidth() + n > screen.getBounds().getWidth()) return;
        if (rectangle.getWidth() + n <= 0) return;
        rectangle.setWidth(rectangle.getWidth() + n);
    }

    private void moveCaptureRectangleHeight(int n) {
        if(rectangle.getHeight() <= 0.0) return;
        if (rectangle.getY() + rectangle.getHeight() + n > screen.getBounds().getHeight()) return;
        if (rectangle.getHeight() + n <= 0) return;
        rectangle.setHeight(rectangle.getHeight() + n);
    }

    private void moveRectangle() {
        rectangle.requestFocus();
        calcPosition();
        dragRectangles();
    }

    private void dragRectangles() {
        controlPane.setPrefWidth(rectangle.getWidth());
        controlPane.setPrefHeight(rectangle.getHeight());
        if (controlPane.getWidth() > 0) {
            controlPane.setVisible(true);
        } else {
            controlPane.setVisible(false);
        }
        dragRectangles.forEach(e->e.setVisible(false));
        if (rectangle.getWidth() > 6) {
            Rectangle rectangle1 = dragRectangles.get(0); // 左上角
            rectangle1.setX(rectangle.getX()-2);
            rectangle1.setY(rectangle.getLayoutY()-2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getWidth() > 8) {
            Rectangle rectangle1 = dragRectangles.get(1); // 右上角
            rectangle1.setX(rectangle.getX() + rectangle.getWidth() -2);
            rectangle1.setY(rectangle.getY()-2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getWidth() > 12) {
            Rectangle rectangle1 = dragRectangles.get(2); // 上中
            rectangle1.setX(rectangle.getX() + rectangle.getWidth()/2 - 2);
            rectangle1.setY(rectangle.getY() -2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getHeight() > 6) {
            Rectangle rectangle1 = dragRectangles.get(3); // 左下角
            rectangle1.setX(rectangle.getX()-2);
            rectangle1.setY(rectangle.getY() + rectangle.getHeight() -2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getHeight() > 8 && rectangle.getWidth() > 8) {
            Rectangle rectangle1 = dragRectangles.get(4); // 右下角
            rectangle1.setX(rectangle.getX() + rectangle.getWidth() -2);
            rectangle1.setY(rectangle.getY() + rectangle.getHeight() -2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getHeight() > 12 && rectangle.getWidth() > 12) {
            Rectangle rectangle1 = dragRectangles.get(5); // 下中
            rectangle1.setX(rectangle.getX() + rectangle.getWidth()/2-2);
            rectangle1.setY(rectangle.getY() + rectangle.getHeight()-2);
            rectangle1.setVisible(true);
        }

        if (rectangle.getHeight() > 6) {
            Rectangle rectangle1 = dragRectangles.get(6); // 左中
            rectangle1.setX(rectangle.getX()-2);
            rectangle1.setY(rectangle.getY() + rectangle.getHeight()/2-2);
            rectangle1.setVisible(true);
        }
        if (rectangle.getHeight() > 8) {
            Rectangle rectangle1 = dragRectangles.get(7); // 右中
            rectangle1.setX(rectangle.getX() + rectangle.getWidth()-2);
            rectangle1.setY(rectangle.getY()+ rectangle.getHeight()/2-2);
            rectangle1.setVisible(true);
        }
    }

    // 计算截图尺寸大小的位置
    private void calcPosition() {
        int w = (int)(rectangle.getWidth()-2);
        int h = (int)(rectangle.getHeight()-2);
        w = w < 0 ? 0 : w;
        h = h < 0 ? 0 : h;
        String text = String.format("X:%s, Y:%s, 宽度:%s, 高度:%s", (int)rectangle.getX(), (int)rectangle.getY(), w, h);
        positionLabel.setStyle("-fx-text-fill: black");
        if (rectangle.getY() > 30) {
            positionLabel.setText(text);

            controlPane.setLayoutX(rectangle.getX());
            controlPane.setLayoutY(rectangle.getY() - 30);
        } else {
            positionLabel.setText(text);

            controlPane.setLayoutX(rectangle.getX());
            controlPane.setLayoutY(rectangle.getY() + 10);
        }
    }

    private WritableImage captureScreen(double x, double y, double w, double h, boolean scaleToFit) {
        return robot.getScreenCapture(null, x, y, w, h, scaleToFit);
    }

    private void captureFullScreen() {
        double w = screen.getBounds().getWidth();
        double h = screen.getBounds().getHeight();
        WritableImage writableImage = captureScreen(0, 0, w, h, false);
        fullScreenImageView.setFitWidth(w);
        fullScreenImageView.setFitHeight(h);
        fullScreenImageView.setImage(writableImage);
    }

    private void playTipAnination() {
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(new KeyFrame(new Duration(0), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(300), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(500), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(700), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(900), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1100), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1300), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1500), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1700), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1900), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(2000), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.setOnFinished((e)-> tip.setVisible(false));
        timeline.playFromStart();
    }

}
